Load libraries

library(tidyverse)
── Attaching core tidyverse packages ──────────────────────────────────────────────────────────────────── tidyverse 2.0.0 ──
✔ dplyr     1.1.2     ✔ readr     2.1.4
✔ forcats   1.0.0     ✔ stringr   1.5.0
✔ ggplot2   3.5.1     ✔ tibble    3.2.1
✔ lubridate 1.9.2     ✔ tidyr     1.3.0
✔ purrr     1.0.1     ── Conflicts ────────────────────────────────────────────────────────────────────────────────────── tidyverse_conflicts() ──
✖ dplyr::filter() masks stats::filter()
✖ dplyr::lag()    masks stats::lag()
ℹ Use the ]8;;http://conflicted.r-lib.org/conflicted package]8;; to force all conflicts to become errors
library(googlesheets4)
library(fuzzyjoin)

Import google sheets of Billiken League data

Load FanGraphs Depth Charts Projections files

hitter_projections <- read_csv("hitter_projections_2025.csv") %>% 
  mutate(Name = stringi::stri_trans_general(Name, "Latin-ASCII"))
Rows: 618 Columns: 74── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (4): Name, Team, NameASCII, PlayerId
dbl (45): G, PA, AB, H, 1B, 2B, 3B, HR, R, RBI, BB, IBB, SO, HBP, SF, SH, SB, CS, AVG, BB%, K%, BB/K, OBP, SLG, wOBA, OP...
lgl (25): GDP, InterSD, InterSK, IntraSD, Vol, Skew, Dim, P10, P20, P30, P40, P50, P60, P70, P80, P90, TT10, TT20, TT30,...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
pitcher_projections <- read_csv("pitcher_projections_2025.csv") %>% 
  mutate(Name = stringi::stri_trans_general(Name, "Latin-ASCII"))
Rows: 837 Columns: 69── Column specification ────────────────────────────────────────────────────────────────────────────────────────────────────
Delimiter: ","
chr  (4): Name, Team, NameASCII, PlayerId
dbl (37): W, L, QS, ERA, G, GS, SV, HLD, IP, TBF, H, R, ER, HR, BB, HBP, SO, K/9, BB/9, K/BB, HR/9, K%, BB%, K-BB%, AVG,...
lgl (28): BS, IBB, GB%, HR/FB, InterSD, InterSK, IntraSD, Vol, Skew, Dim, P10, P20, P30, P40, P50, P60, P70, P80, P90, T...
ℹ Use `spec()` to retrieve the full column specification for this data.
ℹ Specify the column types or set `show_col_types = FALSE` to quiet this message.
hitter_projections
pitcher_projections
NA

Filter out non-player rows

prefreeze_rosters <- prefreeze_rosters %>% 
  filter(!is.na(player)) %>% 
  mutate(across(c("salary"), ~gsub("\\$", "", .) %>% as.numeric))
Warning: There was 1 warning in `mutate()`.
ℹ In argument: `across(c("salary"), ~gsub("\\$", "", .) %>% as.numeric)`.
Caused by warning in `gsub("\\$", "", salary) %>% as.numeric`:
! NAs introduced by coercion
prefreeze_rosters
  #filter(billikenTeam == "Blue Socks")

Merge projections with pre-freeze rosters

hitter_projections %>% 
#Find NL projections only
  filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  #left_join(prefreeze_rosters, join_by('Name'=='player')) 
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2)

pitcher_projections %>% 
#Find NL projections only
  filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  #left_join(prefreeze_rosters, join_by('Name'=='player')) 
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2)
NA

Team Totals

(hitter_team_totals <- hitter_projections %>% 
#Find NL projections only
  filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2) %>% 
  group_by(billikenTeam) %>% 
  summarize(n=n(), PA = sum(PA), AB = sum(AB), H = sum(H), HR = sum(HR), R = sum(R), RBI = sum(RBI), SB = sum(SB), AVG = sum(H)/sum(AB)))


(pitcher_team_totals <- pitcher_projections %>% 
#Find NL projections only
  filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2) %>% 
  group_by(billikenTeam) %>% 
  summarize(n=n(), W = sum(W), SV = sum(SV), IP = sum(IP), SO = sum(SO), ER = sum(ER), H = sum(H), BB = sum(BB), ERA = sum(ER)*9/sum(IP), WHIP = (sum(H)+sum(BB))/sum(IP)) )
NA
NA

Team Standings

#Rank Team Totals
n_teams <- pull(count(hitter_team_totals %>% filter(!is.na(billikenTeam)) %>% distinct(billikenTeam)))

hitter_points <- hitter_team_totals %>% 
  filter(!is.na(billikenTeam)) %>% 
  mutate(hr = n_teams+1 - dense_rank(desc(HR)), r = n_teams+1 - dense_rank(desc(R)), rbi = n_teams+1 - dense_rank(desc(RBI)), sb = n_teams+1 - dense_rank(desc(SB)), avg = n_teams+1 - dense_rank(desc(AVG))) %>% 
  mutate(hr_pct = (hr-1)/(n_teams-1), r_pct = (r-1)/(n_teams-1), rbi_pct = (rbi-1)/(n_teams-1), sb_pct = (sb-1)/(n_teams-1), avg_pct = (avg-1)/(n_teams-1)) %>% 
  mutate(hit = hr + r + rbi + sb + avg) %>% 
  arrange(desc(hit))

hitter_points

pitcher_points <- pitcher_team_totals %>% 
  filter(!is.na(billikenTeam)) %>% 
  mutate(w = n_teams+1 - dense_rank(desc(W)), sv = n_teams+1 - dense_rank(desc(SV)), so = n_teams+1 - dense_rank(desc(SO)), era = n_teams+1 - dense_rank(ERA), whip = n_teams+1 - dense_rank(WHIP)) %>%
  mutate(w_pct = (w-1)/(n_teams-1), sv_pct = (sv-1)/(n_teams-1), so_pct = (so-1)/(n_teams-1), era_pct = (era-1)/(n_teams-1), whip_pct = (whip-1)/(n_teams-1)) %>%
  mutate(pit = w + sv + so + era + whip) %>% 
  arrange(desc(pit))

pitcher_points
NA

Project category variability

ggplot(hitter_points, aes(HR, hr_pct)) +
  geom_point() +
  stat_smooth(method="glm", method.args = list(family=binomial))


ggplot(pitcher_points, aes(ERA, era_pct)) +
  geom_point() +
  stat_smooth(method="glm", method.args = list(family=binomial))

Fit logistic regression curves

hr_model_glm <- glm(hr_pct ~ HR, data = hitter_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
hitter_points$hr_pts_pred = predict(hr_model_glm, hitter_points, type="response")*8+1

r_model_glm <- glm(r_pct ~ R, data = hitter_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
hitter_points$r_pts_pred = predict(r_model_glm, hitter_points, type="response")*8+1

rbi_model_glm <- glm(rbi_pct ~ RBI, data = hitter_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
hitter_points$rbi_pts_pred = predict(rbi_model_glm, hitter_points, type="response")*8+1

sb_model_glm <- glm(sb_pct ~ SB, data = hitter_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
hitter_points$sb_pts_pred = predict(sb_model_glm, hitter_points, type="response")*8+1

avg_model_glm <- glm(avg_pct ~ AVG, data = hitter_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
hitter_points$avg_pts_pred = predict(hr_model_glm, hitter_points, type="response")*8+1

(hitter_points <- hitter_points %>% 
  mutate(hitter_points_pred = hr_pts_pred + r_pts_pred + rbi_pts_pred + sb_pts_pred + avg_pts_pred) %>% 
    arrange(desc(hit)))


#instead of running this on teams, run this for every potential drafted player to project points impact of each player based on the current composition of each roster

w_model_glm <- glm(w_pct ~ W, data = pitcher_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
pitcher_points$w_pts_pred = predict(w_model_glm, pitcher_points, type="response")*8+1

sv_model_glm <- glm(sv_pct ~ SV, data = pitcher_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
pitcher_points$sv_pts_pred = predict(sv_model_glm, pitcher_points, type="response")*8+1

so_model_glm <- glm(so_pct ~ SO, data = pitcher_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
pitcher_points$so_pts_pred = predict(so_model_glm, pitcher_points, type="response")*8+1

era_model_glm <- glm(era_pct ~ ERA, data = pitcher_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
pitcher_points$era_pts_pred = predict(era_model_glm, pitcher_points, type="response")*8+1

whip_model_glm <- glm(whip_pct ~ WHIP, data = pitcher_points, family = "binomial")
Warning: non-integer #successes in a binomial glm!
pitcher_points$whip_pts_pred = predict(whip_model_glm, pitcher_points, type="response")*8+1

(pitcher_points <- pitcher_points %>% 
  mutate(pitcher_points_pred = w_pts_pred + sv_pts_pred + so_pts_pred + era_pts_pred + whip_pts_pred) %>% 
    arrange(desc(pitcher_points_pred)))
NA
hitter_points %>% 
  inner_join(pitcher_points, by = join_by(billikenTeam)) %>% 
  mutate(total = round(hitter_points_pred + pitcher_points_pred,1)) %>% 
  #mutate(total = hit + pit) %>% 
  select(billikenTeam, total, hr, r, rbi, sb, avg, w, sv, so, era, whip, total) %>% 
  arrange(desc(total)) 

Player projected point impact (average, not situation-based)

Simple linear model by category

hr_model <- lm(hr ~ HR, hitter_points) 
r_model <- lm(r ~ R, hitter_points) 
rbi_model <- lm(rbi ~ RBI, hitter_points) 
sb_model <- lm(sb ~ SB, hitter_points) 
avg_model <- lm(avg ~ AVG, hitter_points) 

w_model <- lm(w ~ W, pitcher_points) 
sv_model <- lm(sv ~ SV, pitcher_points) 
so_model <- lm(so ~ SO, pitcher_points) 
era_model <- lm(era ~ ERA, pitcher_points) 
whip_model <- lm(whip ~ WHIP, pitcher_points) 

hr_factor = hr_model$coefficients["HR"]
r_factor = r_model$coefficients["R"]
rbi_factor = rbi_model$coefficients["RBI"]
sb_factor = sb_model$coefficients["SB"]
avg_factor = avg_model$coefficients["AVG"]

melonheads_h <- pull(hitter_team_totals %>% filter(billikenTeam == "Melonheads") %>% select(H))
melonheads_ab <- pull(hitter_team_totals %>% filter(billikenTeam == "Melonheads") %>% select(AB))

w_factor = w_model$coefficients["W"]
sv_factor = sv_model$coefficients["SV"]
so_factor = so_model$coefficients["SO"]
era_factor = era_model$coefficients["ERA"]
whip_factor = whip_model$coefficients["WHIP"]

melonheads_ip <- pull(pitcher_team_totals %>% filter(billikenTeam == "Melonheads") %>% select(IP))
melonheads_er <- pull(pitcher_team_totals %>% filter(billikenTeam == "Melonheads") %>% select(ER))
melonheads_wh <- pull(pitcher_team_totals %>% filter(billikenTeam == "Melonheads") %>% select(BB)) + pull(pitcher_team_totals %>% filter(billikenTeam == "Melonheads") %>% select(H))

Build list of project draft value

#List of available players
hitter_projections %>% 
  filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2) %>% 
  filter(is.na(billikenTeam)) %>% 
  mutate(AVG = round(AVG,3)) %>% 
  mutate(point_value = round(HR * hr_factor + R * r_factor + RBI * rbi_factor + SB * sb_factor + avg_factor * ((melonheads_h + H)/(melonheads_ab + AB) - melonheads_h/melonheads_ab),1)) %>%  
  select(Name, Team, PA, HR, R, RBI, SB, AVG, point_value) %>% 
  arrange(desc(point_value))
NA
hitter_projections <- hitter_projections %>% 
  mutate(point_value = round(HR * hr_factor + R * r_factor + RBI * rbi_factor + SB * sb_factor + avg_factor * ((melonheads_h + H)/(melonheads_ab + AB) - melonheads_h/melonheads_ab),1))

pitcher_projections <- pitcher_projections %>% 
  mutate(point_value = round(W * w_factor + SV * sv_factor + SO * so_factor + era_factor * (9*(melonheads_er + ER)/(melonheads_ip + IP) - 9*melonheads_er/melonheads_ip) + whip_factor * ((melonheads_wh + BB + H)/(melonheads_ip + IP) - melonheads_wh/melonheads_ip),1))
bind_rows(hitter_projections, pitcher_projections) %>% 
  #filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2) %>% 
  filter(billikenTeam == "Melonheads") %>% 
  mutate(AVG = round(AVG,3), ERA = round(ERA,2), WHIP = round(WHIP,2)) %>%  
  select(Name, Team, PA, HR, R, RBI, SB, AVG, IP, W, SV, SO, ERA, WHIP, point_value) %>% 
  arrange(desc(point_value))
NA

All projected players with billiken league details

projected_players <- bind_rows(hitter_projections, pitcher_projections) %>% 
  filter(Team %in% c('ATL','LAD','SDP','ARI','NYM','PHI','MIL','STL','CHC','SFG','CIN','COL','PIT','MIA','WSN','NA')) %>%
  stringdist_left_join(prefreeze_rosters, by = c("Name" = "player"), max_dist = 2) %>% 
  stringdist_left_join(positions, by = c("Name" = "player"), max_dist = 2) %>% 
  #stringdist_left_join(salaries, by = c("Name" = "Player"), max_dist = 2) %>% 
  #mutate(salary = case_when(!is.na(billikenTeam) ~ salary, TRUE ~ new_salary)) %>% 
  #filter(is.na(Owner) & !is.na(billikenTeam)) %>% 
  mutate(AVG = round(AVG,3), ERA = round(ERA,2), WHIP = round(WHIP,2), SO = case_when(IP == 0 ~ NA, IP > 0 ~ SO)) %>%  
  mutate(HR = case_when(PA == 0 ~ NA, PA > 0 ~ HR), R = case_when(PA == 0 ~ NA, PA > 0 ~ R), AVG = case_when(PA == 0 ~ NA, PA > 0 ~ AVG)) %>% 
  select(Name, billikenTeam, contract, salary, Team, PA, HR, R, RBI, SB, AVG, IP, W, SV, SO, ERA, WHIP, point_value, p_c, p_1b, p_2b, p_3b, p_ss, p_of, p_ci, p_mi, p_dh) %>% 
  arrange(desc(point_value)) #%>% 
  #filter(billikenTeam == "Melonheads") 

projected_players
NA

Replacement level example plot

pos <- projected_players %>% 
  filter(p_c == 1) %>% 
  mutate(rank_c = row_number(desc(point_value)))

ggplot(pos, aes(x=rank_c, y=point_value)) +
  geom_point() +
  geom_vline(xintercept = 21, color = "red")

Calculate replacement level by position (with no shared positions)

rl_c <- projected_players %>% 
  filter(p_c == 1) %>% 
  filter(row_number(desc(point_value)) == 21L) %>% 
  mutate(pos = 'c') %>% 
  select(Name, pos, point_value)

rl_1b <- projected_players %>% 
  filter(p_1b == 1) %>% 
  filter(row_number(desc(point_value)) == 16L) %>% 
  mutate(pos = '1b') %>% 
  select(Name, pos, point_value)

rl_2b <- projected_players %>% 
  filter(p_2b == 1) %>% 
  filter(row_number(desc(point_value)) == 16L) %>% 
  mutate(pos = '2b') %>% 
  select(Name, pos, point_value)

rl_3b <- projected_players %>% 
  filter(p_3b == 1) %>% 
  filter(row_number(desc(point_value)) == 16L) %>% 
  mutate(pos = '3b') %>% 
  select(Name, pos, point_value)

rl_ss <- projected_players %>% 
  filter(p_ss == 1) %>% 
  filter(row_number(desc(point_value)) == 16L) %>% 
  mutate(pos = 'ss') %>% 
  select(Name, pos, point_value)

rl_of <- projected_players %>% 
  filter(p_of == 1) %>% 
  filter(row_number(desc(point_value)) == 51L) %>% 
  mutate(pos = 'of') %>% 
  select(Name, pos, point_value)

rl_ci <- projected_players %>% 
  filter(p_ci == 1) %>% 
  filter(row_number(desc(point_value)) == 31L) %>% 
  mutate(pos = 'ci') %>% 
  select(Name, pos, point_value)

rl_mi <- projected_players %>% 
  filter(p_mi == 1) %>% 
  filter(row_number(desc(point_value)) == 31L) %>% 
  mutate(pos = 'mi') %>% 
  select(Name, pos, point_value)

rl_dh <- projected_players %>% 
  filter(p_dh == 1) %>% 
  filter(row_number(desc(point_value)) == 11L) %>% 
  mutate(pos = 'dh') %>% 
  select(Name, pos, point_value)

rl_util <- projected_players %>% 
  filter(row_number(desc(point_value)) == 151L) %>% 
  mutate(pos = 'util') %>% 
  select(Name, pos, point_value)

rl_p <- projected_players %>% 
  filter(IP > 0) %>% 
  filter(row_number(desc(point_value)) == 91L) %>% 
  mutate(pos = 'p') %>% 
  select(Name, pos, point_value)

(replacement_level <- rbind(rl_c, rl_1b, rl_2b, rl_3b, rl_ss, rl_of, rl_ci, rl_mi, rl_dh, rl_util, rl_p))
NA

Note - multiposition players not totally clean here.

Assume that we use the lowest replacement level of any position a player qualifies for.

Points Above Replacement

par <- projected_players %>% 
  mutate(repl = case_when(IP > 0 ~ 0.9, 
                          p_c == 1 ~ 0.4,
                          p_3b == 1 ~ 1.1,
                          p_of == 1 ~ 1.5,
                          p_ci == 1 ~ 1.5,
                          p_1b == 1 ~ 1.8,
                          .default = 2.1)
         ) %>% 
  mutate(par = point_value - repl) %>% 
  arrange(desc(par)) %>% 
  select(Name, Team, billikenTeam, contract, salary, point_value, repl, par, PA, HR, R, RBI, SB, AVG, IP, W, SV, SO, ERA, WHIP, p_c, p_1b, p_2b, p_3b, p_ss, p_of, p_ci, p_mi, p_dh)

par
ggplot(par, aes(par,salary)) +
  geom_point() +
  geom_smooth(method="lm")



ev_model <- lm(salary ~ par, par) 


#par$ev <- par$par*2.118+4.840
par$ev <- par$par*3.385+5.154

par$surplus <- round(par$ev - par$salary,1)
par$ev <- round(par$ev,1)

Projections by Billiken Team

Add in new salaries

Project/simulate draft - Project/simulate next draft pick

Factor in salaries and cap

Build form for draft picks with projected standings

ggplot(projected_draft_eligible, aes(x = pick, y = ev)) + 
  scale_x_continuous(breaks=seq(1, 101, 10)) +
  theme(axis.text.x = element_text(angle = 90, vjust = 0.5, hjust = 1)) +
  xlim(0,100) +
  geom_smooth(formula = y ~ log(x)) +
  geom_point()
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

LS0tCnRpdGxlOiAiSW1wb3J0IEJpbGxpa2VuIFNoZWV0cyIKb3V0cHV0OiBodG1sX25vdGVib29rCi0tLQoKTG9hZCBsaWJyYXJpZXMKCmBgYHtyfQpsaWJyYXJ5KHRpZHl2ZXJzZSkKbGlicmFyeShnb29nbGVzaGVldHM0KQpsaWJyYXJ5KGZ1enp5am9pbikKCmBgYAoKSW1wb3J0IGdvb2dsZSBzaGVldHMgb2YgQmlsbGlrZW4gTGVhZ3VlIGRhdGEKYGBge3J9CgojUHVsbCBwcmUtZHJhZnQgZGF0YQpwcmVmcmVlemVfcm9zdGVycyA8LSByZWFkX3NoZWV0KCJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xWmpsQlRSQW5XOHZUemRyNHJZLWNpUVdtWU1QdkVGNXh0R1FrVU5MZzRhMC9lZGl0P2dpZD0wI2dpZD0wIiwgc2hlZXQgPSAiUHJlRnJlZXplUm9zdGVycyIsIGNvbF90eXBlcyA9ICdjY2NjY2NjJykgJT4lIAogIGZpbHRlcighaXMubmEocGxheWVyKSkKCiNJZiB5b3UgY3JlYXRlZCBhIG5ldyBnb29nbGUgc2hlZXQsIGRvbid0IGZvcmdldCB0byBjaGFuZ2Ugc2hhcmluZyBwZXJtaXNzaW9ucyB0byAiYW55b25lIHdpdGggdGhlIGxpbmsgY2FuIGVkaXQiIG9yIHlvdSB3aWxsIGdldCBPQXV0aCBlcnJvcnMKZnJvemVuX3Jvc3RlcnMgPC0gcmVhZF9zaGVldCgiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVpqbEJUUkFuVzh2VHpkcjRyWS1jaVFXbVlNUHZFRjV4dEdRa1VOTGc0YTAvZWRpdD9naWQ9MTg3MTY2NjMwMyNnaWQ9MTg3MTY2NjMwMyIsIHNoZWV0ID0gIkZyb3plblJvc3RlcnMiLCBjb2xfdHlwZXMgPSAnY2NjY2NjJykKZHJhZnQgPC0gcmVhZF9zaGVldCgiaHR0cHM6Ly9kb2NzLmdvb2dsZS5jb20vc3ByZWFkc2hlZXRzL2QvMVpqbEJUUkFuVzh2VHpkcjRyWS1jaVFXbVlNUHZFRjV4dEdRa1VOTGc0YTAvZWRpdD9naWQ9MTAwODAwNDcyOSNnaWQ9MTAwODAwNDcyOSIsIHNoZWV0ID0gIkRyYWZ0IiwgY29sX3R5cGVzID0gJ2NpaWljY2NjY2MnKQpzYWxhcmllcyA8LSByZWFkX3NoZWV0KCJodHRwczovL2RvY3MuZ29vZ2xlLmNvbS9zcHJlYWRzaGVldHMvZC8xWmpsQlRSQW5XOHZUemRyNHJZLWNpUVdtWU1QdkVGNXh0R1FrVU5MZzRhMC9lZGl0P2dpZD0xMTIzOTUyNTY3I2dpZD0xMTIzOTUyNTY3Iiwgc2hlZXQgPSAiU2FsYXJpZXMiLCBjb2xfdHlwZXMgPSAnY2NjJykgJT4lIAogICAgcmVuYW1lKG5ld19zYWxhcnkgPSBTYWxhcnkpICAlPiUgCiAgICBmaWx0ZXIoIWlzLm5hKFBsYXllcikpICU+JSAgCiAgICBtdXRhdGUoYWNyb3NzKGMoIm5ld19zYWxhcnkiKSwgfmdzdWIoIlxcJCIsICIiLCAuKSAlPiUgYXMubnVtZXJpYykpCnBvc2l0aW9ucyA8LSBzdXBwcmVzc1dhcm5pbmdzKHJlYWRfc2hlZXQoImh0dHBzOi8vZG9jcy5nb29nbGUuY29tL3NwcmVhZHNoZWV0cy9kLzFaamxCVFJBblc4dlR6ZHI0clktY2lRV21ZTVB2RUY1eHRHUWtVTkxnNGEwL2VkaXQ/Z2lkPTYwNTE2MjQzNyNnaWQ9NjA1MTYyNDM3Iiwgc2hlZXQgPSAiUG9zaXRpb25zIiwgY29sX3R5cGVzID0gJ2NpaWlpaWlpaWlpaScpICU+JSAKICAgIG11dGF0ZShQTEFZRVIgPSBnc3ViKCJcbi4qIiwiIixQTEFZRVIpKSAlPiUgCiAgICBtdXRhdGUoUExBWUVSID0gZ3N1YigiRFRELioiLCIiLFBMQVlFUikpICU+JQogICAgbXV0YXRlKHBfb2YgPSBjYXNlX3doZW4oUkYgPT0gMSB+IDEsIENGID09IDEgfiAxLCBMRiA9PSAxIH4gMSwgLmRlZmF1bHQgPSAwKSkgJT4lCiAgICBtdXRhdGUocF9jaSA9IGNhc2Vfd2hlbihgMUJgID09IDEgfiAxLCBgM0JgID09IDEgfiAxLCAuZGVmYXVsdCA9IDApKSAlPiUKICAgIG11dGF0ZShwX21pID0gY2FzZV93aGVuKGAyQmAgPT0gMSB+IDEsIFNTID09IDEgfiAxLCAuZGVmYXVsdCA9IDApKSAlPiUgIAogICAgcmVuYW1lKHBsYXllciA9IFBMQVlFUiwgcF9jID0gQywgcF8xYiA9IGAxQmAsIHBfMmIgPSBgMkJgLCBwXzNiID0gYDNCYCwgcF9zcyA9IFNTLCBwX2RoID0gREgpICU+JSAKICAgIHNlbGVjdChwbGF5ZXIsIHBfYywgcF8xYiwgcF8yYiwgcF8zYiwgcF9zcywgcF9vZiwgcF9jaSwgcF9taSwgcF9kaCkpCgpgYGAKCkxvYWQgRmFuR3JhcGhzIERlcHRoIENoYXJ0cyBQcm9qZWN0aW9ucyBmaWxlcwpgYGB7cn0KaGl0dGVyX3Byb2plY3Rpb25zIDwtIHJlYWRfY3N2KCJoaXR0ZXJfcHJvamVjdGlvbnNfMjAyNS5jc3YiKSAlPiUgCiAgbXV0YXRlKE5hbWUgPSBzdHJpbmdpOjpzdHJpX3RyYW5zX2dlbmVyYWwoTmFtZSwgIkxhdGluLUFTQ0lJIikpCnBpdGNoZXJfcHJvamVjdGlvbnMgPC0gcmVhZF9jc3YoInBpdGNoZXJfcHJvamVjdGlvbnNfMjAyNS5jc3YiKSAlPiUgCiAgbXV0YXRlKE5hbWUgPSBzdHJpbmdpOjpzdHJpX3RyYW5zX2dlbmVyYWwoTmFtZSwgIkxhdGluLUFTQ0lJIikpCgpoaXR0ZXJfcHJvamVjdGlvbnMKcGl0Y2hlcl9wcm9qZWN0aW9ucwoKYGBgCgpGaWx0ZXIgb3V0IG5vbi1wbGF5ZXIgcm93cwpgYGB7cn0KcHJlZnJlZXplX3Jvc3RlcnMgPC0gcHJlZnJlZXplX3Jvc3RlcnMgJT4lIAogIGZpbHRlcighaXMubmEocGxheWVyKSkgJT4lIAogIG11dGF0ZShhY3Jvc3MoYygic2FsYXJ5IiksIH5nc3ViKCJcXCQiLCAiIiwgLikgJT4lIGFzLm51bWVyaWMpKQoKcHJlZnJlZXplX3Jvc3RlcnMKICAjZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiQmx1ZSBTb2NrcyIpCgpgYGAKCgpNZXJnZSBwcm9qZWN0aW9ucyB3aXRoIHByZS1mcmVlemUgcm9zdGVycwoKYGBge3J9CmhpdHRlcl9wcm9qZWN0aW9ucyAlPiUgCiNGaW5kIE5MIHByb2plY3Rpb25zIG9ubHkKICBmaWx0ZXIoVGVhbSAlaW4lIGMoJ0FUTCcsJ0xBRCcsJ1NEUCcsJ0FSSScsJ05ZTScsJ1BISScsJ01JTCcsJ1NUTCcsJ0NIQycsJ1NGRycsJ0NJTicsJ0NPTCcsJ1BJVCcsJ01JQScsJ1dTTicsJ05BJykpICU+JQogICNsZWZ0X2pvaW4ocHJlZnJlZXplX3Jvc3RlcnMsIGpvaW5fYnkoJ05hbWUnPT0ncGxheWVyJykpIAogIHN0cmluZ2Rpc3RfbGVmdF9qb2luKHByZWZyZWV6ZV9yb3N0ZXJzLCBieSA9IGMoIk5hbWUiID0gInBsYXllciIpLCBtYXhfZGlzdCA9IDIpCgpwaXRjaGVyX3Byb2plY3Rpb25zICU+JSAKI0ZpbmQgTkwgcHJvamVjdGlvbnMgb25seQogIGZpbHRlcihUZWFtICVpbiUgYygnQVRMJywnTEFEJywnU0RQJywnQVJJJywnTllNJywnUEhJJywnTUlMJywnU1RMJywnQ0hDJywnU0ZHJywnQ0lOJywnQ09MJywnUElUJywnTUlBJywnV1NOJywnTkEnKSkgJT4lCiAgI2xlZnRfam9pbihwcmVmcmVlemVfcm9zdGVycywgam9pbl9ieSgnTmFtZSc9PSdwbGF5ZXInKSkgCiAgc3RyaW5nZGlzdF9sZWZ0X2pvaW4ocHJlZnJlZXplX3Jvc3RlcnMsIGJ5ID0gYygiTmFtZSIgPSAicGxheWVyIiksIG1heF9kaXN0ID0gMikKCmBgYAoKVGVhbSBUb3RhbHMKYGBge3J9CihoaXR0ZXJfdGVhbV90b3RhbHMgPC0gaGl0dGVyX3Byb2plY3Rpb25zICU+JSAKI0ZpbmQgTkwgcHJvamVjdGlvbnMgb25seQogIGZpbHRlcihUZWFtICVpbiUgYygnQVRMJywnTEFEJywnU0RQJywnQVJJJywnTllNJywnUEhJJywnTUlMJywnU1RMJywnQ0hDJywnU0ZHJywnQ0lOJywnQ09MJywnUElUJywnTUlBJywnV1NOJywnTkEnKSkgJT4lCiAgc3RyaW5nZGlzdF9sZWZ0X2pvaW4ocHJlZnJlZXplX3Jvc3RlcnMsIGJ5ID0gYygiTmFtZSIgPSAicGxheWVyIiksIG1heF9kaXN0ID0gMikgJT4lIAogIGdyb3VwX2J5KGJpbGxpa2VuVGVhbSkgJT4lIAogIHN1bW1hcml6ZShuPW4oKSwgUEEgPSBzdW0oUEEpLCBBQiA9IHN1bShBQiksIEggPSBzdW0oSCksIEhSID0gc3VtKEhSKSwgUiA9IHN1bShSKSwgUkJJID0gc3VtKFJCSSksIFNCID0gc3VtKFNCKSwgQVZHID0gc3VtKEgpL3N1bShBQikpKQoKCihwaXRjaGVyX3RlYW1fdG90YWxzIDwtIHBpdGNoZXJfcHJvamVjdGlvbnMgJT4lIAojRmluZCBOTCBwcm9qZWN0aW9ucyBvbmx5CiAgZmlsdGVyKFRlYW0gJWluJSBjKCdBVEwnLCdMQUQnLCdTRFAnLCdBUkknLCdOWU0nLCdQSEknLCdNSUwnLCdTVEwnLCdDSEMnLCdTRkcnLCdDSU4nLCdDT0wnLCdQSVQnLCdNSUEnLCdXU04nLCdOQScpKSAlPiUKICBzdHJpbmdkaXN0X2xlZnRfam9pbihwcmVmcmVlemVfcm9zdGVycywgYnkgPSBjKCJOYW1lIiA9ICJwbGF5ZXIiKSwgbWF4X2Rpc3QgPSAyKSAlPiUgCiAgZ3JvdXBfYnkoYmlsbGlrZW5UZWFtKSAlPiUgCiAgc3VtbWFyaXplKG49bigpLCBXID0gc3VtKFcpLCBTViA9IHN1bShTViksIElQID0gc3VtKElQKSwgU08gPSBzdW0oU08pLCBFUiA9IHN1bShFUiksIEggPSBzdW0oSCksIEJCID0gc3VtKEJCKSwgRVJBID0gc3VtKEVSKSo5L3N1bShJUCksIFdISVAgPSAoc3VtKEgpK3N1bShCQikpL3N1bShJUCkpICkKCgpgYGAKVGVhbSBTdGFuZGluZ3MKYGBge3J9CiNSYW5rIFRlYW0gVG90YWxzCm5fdGVhbXMgPC0gcHVsbChjb3VudChoaXR0ZXJfdGVhbV90b3RhbHMgJT4lIGZpbHRlcighaXMubmEoYmlsbGlrZW5UZWFtKSkgJT4lIGRpc3RpbmN0KGJpbGxpa2VuVGVhbSkpKQoKaGl0dGVyX3BvaW50cyA8LSBoaXR0ZXJfdGVhbV90b3RhbHMgJT4lIAogIGZpbHRlcighaXMubmEoYmlsbGlrZW5UZWFtKSkgJT4lIAogIG11dGF0ZShociA9IG5fdGVhbXMrMSAtIGRlbnNlX3JhbmsoZGVzYyhIUikpLCByID0gbl90ZWFtcysxIC0gZGVuc2VfcmFuayhkZXNjKFIpKSwgcmJpID0gbl90ZWFtcysxIC0gZGVuc2VfcmFuayhkZXNjKFJCSSkpLCBzYiA9IG5fdGVhbXMrMSAtIGRlbnNlX3JhbmsoZGVzYyhTQikpLCBhdmcgPSBuX3RlYW1zKzEgLSBkZW5zZV9yYW5rKGRlc2MoQVZHKSkpICU+JSAKICBtdXRhdGUoaHJfcGN0ID0gKGhyLTEpLyhuX3RlYW1zLTEpLCByX3BjdCA9IChyLTEpLyhuX3RlYW1zLTEpLCByYmlfcGN0ID0gKHJiaS0xKS8obl90ZWFtcy0xKSwgc2JfcGN0ID0gKHNiLTEpLyhuX3RlYW1zLTEpLCBhdmdfcGN0ID0gKGF2Zy0xKS8obl90ZWFtcy0xKSkgJT4lIAogIG11dGF0ZShoaXQgPSBociArIHIgKyByYmkgKyBzYiArIGF2ZykgJT4lIAogIGFycmFuZ2UoZGVzYyhoaXQpKQoKaGl0dGVyX3BvaW50cwoKcGl0Y2hlcl9wb2ludHMgPC0gcGl0Y2hlcl90ZWFtX3RvdGFscyAlPiUgCiAgZmlsdGVyKCFpcy5uYShiaWxsaWtlblRlYW0pKSAlPiUgCiAgbXV0YXRlKHcgPSBuX3RlYW1zKzEgLSBkZW5zZV9yYW5rKGRlc2MoVykpLCBzdiA9IG5fdGVhbXMrMSAtIGRlbnNlX3JhbmsoZGVzYyhTVikpLCBzbyA9IG5fdGVhbXMrMSAtIGRlbnNlX3JhbmsoZGVzYyhTTykpLCBlcmEgPSBuX3RlYW1zKzEgLSBkZW5zZV9yYW5rKEVSQSksIHdoaXAgPSBuX3RlYW1zKzEgLSBkZW5zZV9yYW5rKFdISVApKSAlPiUKICBtdXRhdGUod19wY3QgPSAody0xKS8obl90ZWFtcy0xKSwgc3ZfcGN0ID0gKHN2LTEpLyhuX3RlYW1zLTEpLCBzb19wY3QgPSAoc28tMSkvKG5fdGVhbXMtMSksIGVyYV9wY3QgPSAoZXJhLTEpLyhuX3RlYW1zLTEpLCB3aGlwX3BjdCA9ICh3aGlwLTEpLyhuX3RlYW1zLTEpKSAlPiUKICBtdXRhdGUocGl0ID0gdyArIHN2ICsgc28gKyBlcmEgKyB3aGlwKSAlPiUgCiAgYXJyYW5nZShkZXNjKHBpdCkpCgpwaXRjaGVyX3BvaW50cwoKYGBgCgoKUHJvamVjdCBjYXRlZ29yeSB2YXJpYWJpbGl0eQpgYGB7cn0KZ2dwbG90KGhpdHRlcl9wb2ludHMsIGFlcyhIUiwgaHJfcGN0KSkgKwogIGdlb21fcG9pbnQoKSArCiAgc3RhdF9zbW9vdGgobWV0aG9kPSJnbG0iLCBtZXRob2QuYXJncyA9IGxpc3QoZmFtaWx5PWJpbm9taWFsKSkKCmdncGxvdChwaXRjaGVyX3BvaW50cywgYWVzKEVSQSwgZXJhX3BjdCkpICsKICBnZW9tX3BvaW50KCkgKwogIHN0YXRfc21vb3RoKG1ldGhvZD0iZ2xtIiwgbWV0aG9kLmFyZ3MgPSBsaXN0KGZhbWlseT1iaW5vbWlhbCkpCgpgYGAKCkZpdCBsb2dpc3RpYyByZWdyZXNzaW9uIGN1cnZlcwpgYGB7cn0KaHJfbW9kZWxfZ2xtIDwtIGdsbShocl9wY3QgfiBIUiwgZGF0YSA9IGhpdHRlcl9wb2ludHMsIGZhbWlseSA9ICJiaW5vbWlhbCIpCmhpdHRlcl9wb2ludHMkaHJfcHRzX3ByZWQgPSBwcmVkaWN0KGhyX21vZGVsX2dsbSwgaGl0dGVyX3BvaW50cywgdHlwZT0icmVzcG9uc2UiKSo4KzEKCnJfbW9kZWxfZ2xtIDwtIGdsbShyX3BjdCB+IFIsIGRhdGEgPSBoaXR0ZXJfcG9pbnRzLCBmYW1pbHkgPSAiYmlub21pYWwiKQpoaXR0ZXJfcG9pbnRzJHJfcHRzX3ByZWQgPSBwcmVkaWN0KHJfbW9kZWxfZ2xtLCBoaXR0ZXJfcG9pbnRzLCB0eXBlPSJyZXNwb25zZSIpKjgrMQoKcmJpX21vZGVsX2dsbSA8LSBnbG0ocmJpX3BjdCB+IFJCSSwgZGF0YSA9IGhpdHRlcl9wb2ludHMsIGZhbWlseSA9ICJiaW5vbWlhbCIpCmhpdHRlcl9wb2ludHMkcmJpX3B0c19wcmVkID0gcHJlZGljdChyYmlfbW9kZWxfZ2xtLCBoaXR0ZXJfcG9pbnRzLCB0eXBlPSJyZXNwb25zZSIpKjgrMQoKc2JfbW9kZWxfZ2xtIDwtIGdsbShzYl9wY3QgfiBTQiwgZGF0YSA9IGhpdHRlcl9wb2ludHMsIGZhbWlseSA9ICJiaW5vbWlhbCIpCmhpdHRlcl9wb2ludHMkc2JfcHRzX3ByZWQgPSBwcmVkaWN0KHNiX21vZGVsX2dsbSwgaGl0dGVyX3BvaW50cywgdHlwZT0icmVzcG9uc2UiKSo4KzEKCmF2Z19tb2RlbF9nbG0gPC0gZ2xtKGF2Z19wY3QgfiBBVkcsIGRhdGEgPSBoaXR0ZXJfcG9pbnRzLCBmYW1pbHkgPSAiYmlub21pYWwiKQpoaXR0ZXJfcG9pbnRzJGF2Z19wdHNfcHJlZCA9IHByZWRpY3QoaHJfbW9kZWxfZ2xtLCBoaXR0ZXJfcG9pbnRzLCB0eXBlPSJyZXNwb25zZSIpKjgrMQoKKGhpdHRlcl9wb2ludHMgPC0gaGl0dGVyX3BvaW50cyAlPiUgCiAgbXV0YXRlKGhpdHRlcl9wb2ludHNfcHJlZCA9IGhyX3B0c19wcmVkICsgcl9wdHNfcHJlZCArIHJiaV9wdHNfcHJlZCArIHNiX3B0c19wcmVkICsgYXZnX3B0c19wcmVkKSAlPiUgCiAgICBhcnJhbmdlKGRlc2MoaGl0KSkpCgoKI2luc3RlYWQgb2YgcnVubmluZyB0aGlzIG9uIHRlYW1zLCBydW4gdGhpcyBmb3IgZXZlcnkgcG90ZW50aWFsIGRyYWZ0ZWQgcGxheWVyIHRvIHByb2plY3QgcG9pbnRzIGltcGFjdCBvZiBlYWNoIHBsYXllciBiYXNlZCBvbiB0aGUgY3VycmVudCBjb21wb3NpdGlvbiBvZiBlYWNoIHJvc3RlcgoKYGBgCgpgYGB7cn0KCndfbW9kZWxfZ2xtIDwtIGdsbSh3X3BjdCB+IFcsIGRhdGEgPSBwaXRjaGVyX3BvaW50cywgZmFtaWx5ID0gImJpbm9taWFsIikKcGl0Y2hlcl9wb2ludHMkd19wdHNfcHJlZCA9IHByZWRpY3Qod19tb2RlbF9nbG0sIHBpdGNoZXJfcG9pbnRzLCB0eXBlPSJyZXNwb25zZSIpKjgrMQoKc3ZfbW9kZWxfZ2xtIDwtIGdsbShzdl9wY3QgfiBTViwgZGF0YSA9IHBpdGNoZXJfcG9pbnRzLCBmYW1pbHkgPSAiYmlub21pYWwiKQpwaXRjaGVyX3BvaW50cyRzdl9wdHNfcHJlZCA9IHByZWRpY3Qoc3ZfbW9kZWxfZ2xtLCBwaXRjaGVyX3BvaW50cywgdHlwZT0icmVzcG9uc2UiKSo4KzEKCnNvX21vZGVsX2dsbSA8LSBnbG0oc29fcGN0IH4gU08sIGRhdGEgPSBwaXRjaGVyX3BvaW50cywgZmFtaWx5ID0gImJpbm9taWFsIikKcGl0Y2hlcl9wb2ludHMkc29fcHRzX3ByZWQgPSBwcmVkaWN0KHNvX21vZGVsX2dsbSwgcGl0Y2hlcl9wb2ludHMsIHR5cGU9InJlc3BvbnNlIikqOCsxCgplcmFfbW9kZWxfZ2xtIDwtIGdsbShlcmFfcGN0IH4gRVJBLCBkYXRhID0gcGl0Y2hlcl9wb2ludHMsIGZhbWlseSA9ICJiaW5vbWlhbCIpCnBpdGNoZXJfcG9pbnRzJGVyYV9wdHNfcHJlZCA9IHByZWRpY3QoZXJhX21vZGVsX2dsbSwgcGl0Y2hlcl9wb2ludHMsIHR5cGU9InJlc3BvbnNlIikqOCsxCgp3aGlwX21vZGVsX2dsbSA8LSBnbG0od2hpcF9wY3QgfiBXSElQLCBkYXRhID0gcGl0Y2hlcl9wb2ludHMsIGZhbWlseSA9ICJiaW5vbWlhbCIpCnBpdGNoZXJfcG9pbnRzJHdoaXBfcHRzX3ByZWQgPSBwcmVkaWN0KHdoaXBfbW9kZWxfZ2xtLCBwaXRjaGVyX3BvaW50cywgdHlwZT0icmVzcG9uc2UiKSo4KzEKCihwaXRjaGVyX3BvaW50cyA8LSBwaXRjaGVyX3BvaW50cyAlPiUgCiAgbXV0YXRlKHBpdGNoZXJfcG9pbnRzX3ByZWQgPSB3X3B0c19wcmVkICsgc3ZfcHRzX3ByZWQgKyBzb19wdHNfcHJlZCArIGVyYV9wdHNfcHJlZCArIHdoaXBfcHRzX3ByZWQpICU+JSAKICAgIGFycmFuZ2UoZGVzYyhwaXRjaGVyX3BvaW50c19wcmVkKSkpCgpgYGAKCmBgYHtyfQpoaXR0ZXJfcG9pbnRzICU+JSAKICBpbm5lcl9qb2luKHBpdGNoZXJfcG9pbnRzLCBieSA9IGpvaW5fYnkoYmlsbGlrZW5UZWFtKSkgJT4lIAogIG11dGF0ZSh0b3RhbCA9IHJvdW5kKGhpdHRlcl9wb2ludHNfcHJlZCArIHBpdGNoZXJfcG9pbnRzX3ByZWQsMSkpICU+JSAKICAjbXV0YXRlKHRvdGFsID0gaGl0ICsgcGl0KSAlPiUgCiAgc2VsZWN0KGJpbGxpa2VuVGVhbSwgdG90YWwsIGhyLCByLCByYmksIHNiLCBhdmcsIHcsIHN2LCBzbywgZXJhLCB3aGlwLCB0b3RhbCkgJT4lIAogIGFycmFuZ2UoZGVzYyh0b3RhbCkpIApgYGAKClBsYXllciBwcm9qZWN0ZWQgcG9pbnQgaW1wYWN0IChhdmVyYWdlLCBub3Qgc2l0dWF0aW9uLWJhc2VkKQoKU2ltcGxlIGxpbmVhciBtb2RlbCBieSBjYXRlZ29yeQpgYGB7cn0KaHJfbW9kZWwgPC0gbG0oaHIgfiBIUiwgaGl0dGVyX3BvaW50cykgCnJfbW9kZWwgPC0gbG0ociB+IFIsIGhpdHRlcl9wb2ludHMpIApyYmlfbW9kZWwgPC0gbG0ocmJpIH4gUkJJLCBoaXR0ZXJfcG9pbnRzKSAKc2JfbW9kZWwgPC0gbG0oc2IgfiBTQiwgaGl0dGVyX3BvaW50cykgCmF2Z19tb2RlbCA8LSBsbShhdmcgfiBBVkcsIGhpdHRlcl9wb2ludHMpIAoKd19tb2RlbCA8LSBsbSh3IH4gVywgcGl0Y2hlcl9wb2ludHMpIApzdl9tb2RlbCA8LSBsbShzdiB+IFNWLCBwaXRjaGVyX3BvaW50cykgCnNvX21vZGVsIDwtIGxtKHNvIH4gU08sIHBpdGNoZXJfcG9pbnRzKSAKZXJhX21vZGVsIDwtIGxtKGVyYSB+IEVSQSwgcGl0Y2hlcl9wb2ludHMpIAp3aGlwX21vZGVsIDwtIGxtKHdoaXAgfiBXSElQLCBwaXRjaGVyX3BvaW50cykgCgpocl9mYWN0b3IgPSBocl9tb2RlbCRjb2VmZmljaWVudHNbIkhSIl0Kcl9mYWN0b3IgPSByX21vZGVsJGNvZWZmaWNpZW50c1siUiJdCnJiaV9mYWN0b3IgPSByYmlfbW9kZWwkY29lZmZpY2llbnRzWyJSQkkiXQpzYl9mYWN0b3IgPSBzYl9tb2RlbCRjb2VmZmljaWVudHNbIlNCIl0KYXZnX2ZhY3RvciA9IGF2Z19tb2RlbCRjb2VmZmljaWVudHNbIkFWRyJdCgptZWxvbmhlYWRzX2ggPC0gcHVsbChoaXR0ZXJfdGVhbV90b3RhbHMgJT4lIGZpbHRlcihiaWxsaWtlblRlYW0gPT0gIk1lbG9uaGVhZHMiKSAlPiUgc2VsZWN0KEgpKQptZWxvbmhlYWRzX2FiIDwtIHB1bGwoaGl0dGVyX3RlYW1fdG90YWxzICU+JSBmaWx0ZXIoYmlsbGlrZW5UZWFtID09ICJNZWxvbmhlYWRzIikgJT4lIHNlbGVjdChBQikpCgp3X2ZhY3RvciA9IHdfbW9kZWwkY29lZmZpY2llbnRzWyJXIl0Kc3ZfZmFjdG9yID0gc3ZfbW9kZWwkY29lZmZpY2llbnRzWyJTViJdCnNvX2ZhY3RvciA9IHNvX21vZGVsJGNvZWZmaWNpZW50c1siU08iXQplcmFfZmFjdG9yID0gZXJhX21vZGVsJGNvZWZmaWNpZW50c1siRVJBIl0Kd2hpcF9mYWN0b3IgPSB3aGlwX21vZGVsJGNvZWZmaWNpZW50c1siV0hJUCJdCgptZWxvbmhlYWRzX2lwIDwtIHB1bGwocGl0Y2hlcl90ZWFtX3RvdGFscyAlPiUgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiTWVsb25oZWFkcyIpICU+JSBzZWxlY3QoSVApKQptZWxvbmhlYWRzX2VyIDwtIHB1bGwocGl0Y2hlcl90ZWFtX3RvdGFscyAlPiUgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiTWVsb25oZWFkcyIpICU+JSBzZWxlY3QoRVIpKQptZWxvbmhlYWRzX3doIDwtIHB1bGwocGl0Y2hlcl90ZWFtX3RvdGFscyAlPiUgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiTWVsb25oZWFkcyIpICU+JSBzZWxlY3QoQkIpKSArIHB1bGwocGl0Y2hlcl90ZWFtX3RvdGFscyAlPiUgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiTWVsb25oZWFkcyIpICU+JSBzZWxlY3QoSCkpCgpgYGAKCkJ1aWxkIGxpc3Qgb2YgcHJvamVjdCBkcmFmdCB2YWx1ZQpgYGB7cn0KI0xpc3Qgb2YgYXZhaWxhYmxlIHBsYXllcnMKaGl0dGVyX3Byb2plY3Rpb25zICU+JSAKICBmaWx0ZXIoVGVhbSAlaW4lIGMoJ0FUTCcsJ0xBRCcsJ1NEUCcsJ0FSSScsJ05ZTScsJ1BISScsJ01JTCcsJ1NUTCcsJ0NIQycsJ1NGRycsJ0NJTicsJ0NPTCcsJ1BJVCcsJ01JQScsJ1dTTicsJ05BJykpICU+JQogIHN0cmluZ2Rpc3RfbGVmdF9qb2luKHByZWZyZWV6ZV9yb3N0ZXJzLCBieSA9IGMoIk5hbWUiID0gInBsYXllciIpLCBtYXhfZGlzdCA9IDIpICU+JSAKICBmaWx0ZXIoaXMubmEoYmlsbGlrZW5UZWFtKSkgJT4lIAogIG11dGF0ZShBVkcgPSByb3VuZChBVkcsMykpICU+JSAKICBtdXRhdGUocG9pbnRfdmFsdWUgPSByb3VuZChIUiAqIGhyX2ZhY3RvciArIFIgKiByX2ZhY3RvciArIFJCSSAqIHJiaV9mYWN0b3IgKyBTQiAqIHNiX2ZhY3RvciArIGF2Z19mYWN0b3IgKiAoKG1lbG9uaGVhZHNfaCArIEgpLyhtZWxvbmhlYWRzX2FiICsgQUIpIC0gbWVsb25oZWFkc19oL21lbG9uaGVhZHNfYWIpLDEpKSAlPiUgIAogIHNlbGVjdChOYW1lLCBUZWFtLCBQQSwgSFIsIFIsIFJCSSwgU0IsIEFWRywgcG9pbnRfdmFsdWUpICU+JSAKICBhcnJhbmdlKGRlc2MocG9pbnRfdmFsdWUpKQoKYGBgCgpgYGB7cn0KaGl0dGVyX3Byb2plY3Rpb25zIDwtIGhpdHRlcl9wcm9qZWN0aW9ucyAlPiUgCiAgbXV0YXRlKHBvaW50X3ZhbHVlID0gcm91bmQoSFIgKiBocl9mYWN0b3IgKyBSICogcl9mYWN0b3IgKyBSQkkgKiByYmlfZmFjdG9yICsgU0IgKiBzYl9mYWN0b3IgKyBhdmdfZmFjdG9yICogKChtZWxvbmhlYWRzX2ggKyBIKS8obWVsb25oZWFkc19hYiArIEFCKSAtIG1lbG9uaGVhZHNfaC9tZWxvbmhlYWRzX2FiKSwxKSkKCnBpdGNoZXJfcHJvamVjdGlvbnMgPC0gcGl0Y2hlcl9wcm9qZWN0aW9ucyAlPiUgCiAgbXV0YXRlKHBvaW50X3ZhbHVlID0gcm91bmQoVyAqIHdfZmFjdG9yICsgU1YgKiBzdl9mYWN0b3IgKyBTTyAqIHNvX2ZhY3RvciArIGVyYV9mYWN0b3IgKiAoOSoobWVsb25oZWFkc19lciArIEVSKS8obWVsb25oZWFkc19pcCArIElQKSAtIDkqbWVsb25oZWFkc19lci9tZWxvbmhlYWRzX2lwKSArIHdoaXBfZmFjdG9yICogKChtZWxvbmhlYWRzX3doICsgQkIgKyBIKS8obWVsb25oZWFkc19pcCArIElQKSAtIG1lbG9uaGVhZHNfd2gvbWVsb25oZWFkc19pcCksMSkpCgpgYGAKCgpgYGB7cn0KYmluZF9yb3dzKGhpdHRlcl9wcm9qZWN0aW9ucywgcGl0Y2hlcl9wcm9qZWN0aW9ucykgJT4lIAogICNmaWx0ZXIoVGVhbSAlaW4lIGMoJ0FUTCcsJ0xBRCcsJ1NEUCcsJ0FSSScsJ05ZTScsJ1BISScsJ01JTCcsJ1NUTCcsJ0NIQycsJ1NGRycsJ0NJTicsJ0NPTCcsJ1BJVCcsJ01JQScsJ1dTTicsJ05BJykpICU+JQogIHN0cmluZ2Rpc3RfbGVmdF9qb2luKHByZWZyZWV6ZV9yb3N0ZXJzLCBieSA9IGMoIk5hbWUiID0gInBsYXllciIpLCBtYXhfZGlzdCA9IDIpICU+JSAKICBmaWx0ZXIoYmlsbGlrZW5UZWFtID09ICJNZWxvbmhlYWRzIikgJT4lIAogIG11dGF0ZShBVkcgPSByb3VuZChBVkcsMyksIEVSQSA9IHJvdW5kKEVSQSwyKSwgV0hJUCA9IHJvdW5kKFdISVAsMikpICU+JSAgCiAgc2VsZWN0KE5hbWUsIFRlYW0sIFBBLCBIUiwgUiwgUkJJLCBTQiwgQVZHLCBJUCwgVywgU1YsIFNPLCBFUkEsIFdISVAsIHBvaW50X3ZhbHVlKSAlPiUgCiAgYXJyYW5nZShkZXNjKHBvaW50X3ZhbHVlKSkKCmBgYAoKQWxsIHByb2plY3RlZCBwbGF5ZXJzIHdpdGggYmlsbGlrZW4gbGVhZ3VlIGRldGFpbHMKYGBge3J9CnByb2plY3RlZF9wbGF5ZXJzIDwtIGJpbmRfcm93cyhoaXR0ZXJfcHJvamVjdGlvbnMsIHBpdGNoZXJfcHJvamVjdGlvbnMpICU+JSAKICBmaWx0ZXIoVGVhbSAlaW4lIGMoJ0FUTCcsJ0xBRCcsJ1NEUCcsJ0FSSScsJ05ZTScsJ1BISScsJ01JTCcsJ1NUTCcsJ0NIQycsJ1NGRycsJ0NJTicsJ0NPTCcsJ1BJVCcsJ01JQScsJ1dTTicsJ05BJykpICU+JQogIHN0cmluZ2Rpc3RfbGVmdF9qb2luKHByZWZyZWV6ZV9yb3N0ZXJzLCBieSA9IGMoIk5hbWUiID0gInBsYXllciIpLCBtYXhfZGlzdCA9IDIpICU+JSAKICBzdHJpbmdkaXN0X2xlZnRfam9pbihwb3NpdGlvbnMsIGJ5ID0gYygiTmFtZSIgPSAicGxheWVyIiksIG1heF9kaXN0ID0gMikgJT4lIAogIHN0cmluZ2Rpc3RfbGVmdF9qb2luKHNhbGFyaWVzLCBieSA9IGMoIk5hbWUiID0gIlBsYXllciIpLCBtYXhfZGlzdCA9IDIpICU+JSAKICBtdXRhdGUoc2FsYXJ5ID0gY2FzZV93aGVuKCFpcy5uYShiaWxsaWtlblRlYW0pIH4gc2FsYXJ5LCBUUlVFIH4gbmV3X3NhbGFyeSkpICU+JSAKICAjZmlsdGVyKGlzLm5hKE93bmVyKSAmICFpcy5uYShiaWxsaWtlblRlYW0pKSAlPiUgCiAgbXV0YXRlKEFWRyA9IHJvdW5kKEFWRywzKSwgRVJBID0gcm91bmQoRVJBLDIpLCBXSElQID0gcm91bmQoV0hJUCwyKSwgU08gPSBjYXNlX3doZW4oSVAgPT0gMCB+IE5BLCBJUCA+IDAgfiBTTykpICU+JSAgCiAgbXV0YXRlKEhSID0gY2FzZV93aGVuKFBBID09IDAgfiBOQSwgUEEgPiAwIH4gSFIpLCBSID0gY2FzZV93aGVuKFBBID09IDAgfiBOQSwgUEEgPiAwIH4gUiksIEFWRyA9IGNhc2Vfd2hlbihQQSA9PSAwIH4gTkEsIFBBID4gMCB+IEFWRykpICU+JSAKICBzZWxlY3QoTmFtZSwgYmlsbGlrZW5UZWFtLCBjb250cmFjdCwgc2FsYXJ5LCBUZWFtLCBQQSwgSFIsIFIsIFJCSSwgU0IsIEFWRywgSVAsIFcsIFNWLCBTTywgRVJBLCBXSElQLCBwb2ludF92YWx1ZSwgcF9jLCBwXzFiLCBwXzJiLCBwXzNiLCBwX3NzLCBwX29mLCBwX2NpLCBwX21pLCBwX2RoKSAlPiUgCiAgYXJyYW5nZShkZXNjKHBvaW50X3ZhbHVlKSkgIyU+JSAKICAjZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiTWVsb25oZWFkcyIpIAoKcHJvamVjdGVkX3BsYXllcnMKCmBgYAoKUmVwbGFjZW1lbnQgbGV2ZWwgZXhhbXBsZSBwbG90CmBgYHtyfQpwb3MgPC0gcHJvamVjdGVkX3BsYXllcnMgJT4lIAogIGZpbHRlcihwX2MgPT0gMSkgJT4lIAogIG11dGF0ZShyYW5rX2MgPSByb3dfbnVtYmVyKGRlc2MocG9pbnRfdmFsdWUpKSkKCmdncGxvdChwb3MsIGFlcyh4PXJhbmtfYywgeT1wb2ludF92YWx1ZSkpICsKICBnZW9tX3BvaW50KCkgKwogIGdlb21fdmxpbmUoeGludGVyY2VwdCA9IDIxLCBjb2xvciA9ICJyZWQiKQpgYGAKCgpDYWxjdWxhdGUgcmVwbGFjZW1lbnQgbGV2ZWwgYnkgcG9zaXRpb24gKHdpdGggbm8gc2hhcmVkIHBvc2l0aW9ucykKCmBgYHtyfQpybF9jIDwtIHByb2plY3RlZF9wbGF5ZXJzICU+JSAKICBmaWx0ZXIocF9jID09IDEpICU+JSAKICBmaWx0ZXIocm93X251bWJlcihkZXNjKHBvaW50X3ZhbHVlKSkgPT0gMjFMKSAlPiUgCiAgbXV0YXRlKHBvcyA9ICdjJykgJT4lIAogIHNlbGVjdChOYW1lLCBwb3MsIHBvaW50X3ZhbHVlKQoKcmxfMWIgPC0gcHJvamVjdGVkX3BsYXllcnMgJT4lIAogIGZpbHRlcihwXzFiID09IDEpICU+JSAKICBmaWx0ZXIocm93X251bWJlcihkZXNjKHBvaW50X3ZhbHVlKSkgPT0gMTZMKSAlPiUgCiAgbXV0YXRlKHBvcyA9ICcxYicpICU+JSAKICBzZWxlY3QoTmFtZSwgcG9zLCBwb2ludF92YWx1ZSkKCnJsXzJiIDwtIHByb2plY3RlZF9wbGF5ZXJzICU+JSAKICBmaWx0ZXIocF8yYiA9PSAxKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhwb2ludF92YWx1ZSkpID09IDE2TCkgJT4lIAogIG11dGF0ZShwb3MgPSAnMmInKSAlPiUgCiAgc2VsZWN0KE5hbWUsIHBvcywgcG9pbnRfdmFsdWUpCgpybF8zYiA8LSBwcm9qZWN0ZWRfcGxheWVycyAlPiUgCiAgZmlsdGVyKHBfM2IgPT0gMSkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MocG9pbnRfdmFsdWUpKSA9PSAxNkwpICU+JSAKICBtdXRhdGUocG9zID0gJzNiJykgJT4lIAogIHNlbGVjdChOYW1lLCBwb3MsIHBvaW50X3ZhbHVlKQoKcmxfc3MgPC0gcHJvamVjdGVkX3BsYXllcnMgJT4lIAogIGZpbHRlcihwX3NzID09IDEpICU+JSAKICBmaWx0ZXIocm93X251bWJlcihkZXNjKHBvaW50X3ZhbHVlKSkgPT0gMTZMKSAlPiUgCiAgbXV0YXRlKHBvcyA9ICdzcycpICU+JSAKICBzZWxlY3QoTmFtZSwgcG9zLCBwb2ludF92YWx1ZSkKCnJsX29mIDwtIHByb2plY3RlZF9wbGF5ZXJzICU+JSAKICBmaWx0ZXIocF9vZiA9PSAxKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhwb2ludF92YWx1ZSkpID09IDUxTCkgJT4lIAogIG11dGF0ZShwb3MgPSAnb2YnKSAlPiUgCiAgc2VsZWN0KE5hbWUsIHBvcywgcG9pbnRfdmFsdWUpCgpybF9jaSA8LSBwcm9qZWN0ZWRfcGxheWVycyAlPiUgCiAgZmlsdGVyKHBfY2kgPT0gMSkgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MocG9pbnRfdmFsdWUpKSA9PSAzMUwpICU+JSAKICBtdXRhdGUocG9zID0gJ2NpJykgJT4lIAogIHNlbGVjdChOYW1lLCBwb3MsIHBvaW50X3ZhbHVlKQoKcmxfbWkgPC0gcHJvamVjdGVkX3BsYXllcnMgJT4lIAogIGZpbHRlcihwX21pID09IDEpICU+JSAKICBmaWx0ZXIocm93X251bWJlcihkZXNjKHBvaW50X3ZhbHVlKSkgPT0gMzFMKSAlPiUgCiAgbXV0YXRlKHBvcyA9ICdtaScpICU+JSAKICBzZWxlY3QoTmFtZSwgcG9zLCBwb2ludF92YWx1ZSkKCnJsX2RoIDwtIHByb2plY3RlZF9wbGF5ZXJzICU+JSAKICBmaWx0ZXIocF9kaCA9PSAxKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhwb2ludF92YWx1ZSkpID09IDExTCkgJT4lIAogIG11dGF0ZShwb3MgPSAnZGgnKSAlPiUgCiAgc2VsZWN0KE5hbWUsIHBvcywgcG9pbnRfdmFsdWUpCgpybF91dGlsIDwtIHByb2plY3RlZF9wbGF5ZXJzICU+JSAKICBmaWx0ZXIocm93X251bWJlcihkZXNjKHBvaW50X3ZhbHVlKSkgPT0gMTUxTCkgJT4lIAogIG11dGF0ZShwb3MgPSAndXRpbCcpICU+JSAKICBzZWxlY3QoTmFtZSwgcG9zLCBwb2ludF92YWx1ZSkKCnJsX3AgPC0gcHJvamVjdGVkX3BsYXllcnMgJT4lIAogIGZpbHRlcihJUCA+IDApICU+JSAKICBmaWx0ZXIocm93X251bWJlcihkZXNjKHBvaW50X3ZhbHVlKSkgPT0gOTFMKSAlPiUgCiAgbXV0YXRlKHBvcyA9ICdwJykgJT4lIAogIHNlbGVjdChOYW1lLCBwb3MsIHBvaW50X3ZhbHVlKQoKKHJlcGxhY2VtZW50X2xldmVsIDwtIHJiaW5kKHJsX2MsIHJsXzFiLCBybF8yYiwgcmxfM2IsIHJsX3NzLCBybF9vZiwgcmxfY2ksIHJsX21pLCBybF9kaCwgcmxfdXRpbCwgcmxfcCkpCgpgYGAKTm90ZSAtIG11bHRpcG9zaXRpb24gcGxheWVycyBub3QgdG90YWxseSBjbGVhbiBoZXJlLiAKCkFzc3VtZSB0aGF0IHdlIHVzZSB0aGUgbG93ZXN0IHJlcGxhY2VtZW50IGxldmVsIG9mIGFueSBwb3NpdGlvbiBhIHBsYXllciBxdWFsaWZpZXMgZm9yLgoKClBvaW50cyBBYm92ZSBSZXBsYWNlbWVudApgYGB7cn0KcGFyIDwtIHByb2plY3RlZF9wbGF5ZXJzICU+JSAKICBtdXRhdGUocmVwbCA9IGNhc2Vfd2hlbihJUCA+IDAgfiAwLjksIAogICAgICAgICAgICAgICAgICAgICAgICAgIHBfYyA9PSAxIH4gMC40LAogICAgICAgICAgICAgICAgICAgICAgICAgIHBfM2IgPT0gMSB+IDEuMSwKICAgICAgICAgICAgICAgICAgICAgICAgICBwX29mID09IDEgfiAxLjUsCiAgICAgICAgICAgICAgICAgICAgICAgICAgcF9jaSA9PSAxIH4gMS41LAogICAgICAgICAgICAgICAgICAgICAgICAgIHBfMWIgPT0gMSB+IDEuOCwKICAgICAgICAgICAgICAgICAgICAgICAgICAuZGVmYXVsdCA9IDIuMSkKICAgICAgICAgKSAlPiUgCiAgbXV0YXRlKHBhciA9IHBvaW50X3ZhbHVlIC0gcmVwbCkgJT4lIAogIGFycmFuZ2UoZGVzYyhwYXIpKSAlPiUgCiAgc2VsZWN0KE5hbWUsIFRlYW0sIGJpbGxpa2VuVGVhbSwgY29udHJhY3QsIHNhbGFyeSwgcG9pbnRfdmFsdWUsIHJlcGwsIHBhciwgUEEsIEhSLCBSLCBSQkksIFNCLCBBVkcsIElQLCBXLCBTViwgU08sIEVSQSwgV0hJUCwgcF9jLCBwXzFiLCBwXzJiLCBwXzNiLCBwX3NzLCBwX29mLCBwX2NpLCBwX21pLCBwX2RoKQoKcGFyCmBgYAoKYGBge3J9CmdncGxvdChwYXIsIGFlcyhwYXIsc2FsYXJ5KSkgKwogIGdlb21fcG9pbnQoKSArCiAgZ2VvbV9zbW9vdGgobWV0aG9kPSJsbSIpCgoKZXZfbW9kZWwgPC0gbG0oc2FsYXJ5IH4gcGFyLCBwYXIpIAoKCiNwYXIkZXYgPC0gcGFyJHBhcioyLjExOCs0Ljg0MApwYXIkZXYgPC0gcGFyJHBhciozLjM4NSs1LjE1NAoKcGFyJHN1cnBsdXMgPC0gcm91bmQocGFyJGV2IC0gcGFyJHNhbGFyeSwxKQpwYXIkZXYgPC0gcm91bmQocGFyJGV2LDEpCmBgYAoKClByb2plY3Rpb25zIGJ5IEJpbGxpa2VuIFRlYW0KYGBge3J9CnBhciAlPiUgCiAgI2ZpbHRlcihpcy5uYShPd25lcikgJiAhaXMubmEoYmlsbGlrZW5UZWFtKSkgJT4lIAogICNmaWx0ZXIoSVA+MCkgJT4lIAogIGZpbHRlcihiaWxsaWtlblRlYW0gPT0gIkJsdWUgU29ja3MiKSAlPiUgCiAgcmVsb2NhdGUoc3VycGx1cywgLmFmdGVyID0gcGFyKSAlPiUgCiAgcmVsb2NhdGUoZXYsIC5hZnRlciA9IHBhcikgJT4lIAogIGFycmFuZ2UoZGVzYyhwYXIpKSAKICAjYXJyYW5nZShzdXJwbHVzKSAKCmBgYAoKQWRkIGluIG5ldyBzYWxhcmllcwoKUHJvamVjdC9zaW11bGF0ZSBkcmFmdAotIFByb2plY3Qvc2ltdWxhdGUgbmV4dCBkcmFmdCBwaWNrCgpGYWN0b3IgaW4gc2FsYXJpZXMgYW5kIGNhcAoKQnVpbGQgZm9ybSBmb3IgZHJhZnQgcGlja3Mgd2l0aCBwcm9qZWN0ZWQgc3RhbmRpbmdzCgpgYGB7cn0KcGFyICU+JSAKICAjZmlsdGVyKGlzLm5hKE93bmVyKSAmICFpcy5uYShiaWxsaWtlblRlYW0pKSAlPiUgCiAgI2ZpbHRlcihJUD4wKSAlPiUgCiAgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiQmx1ZSBTb2NrcyIpICU+JSAKICByZWxvY2F0ZShzdXJwbHVzLCAuYWZ0ZXIgPSBwYXIpICU+JSAKICByZWxvY2F0ZShldiwgLmFmdGVyID0gcGFyKSAlPiUgCiAgYXJyYW5nZShkZXNjKHBhcikpIAogICNhcnJhbmdlKGRlc2Moc3VycGx1cykpCgpgYGAKCmBgYHtyfQojUHJvamVjdGVkIGZyZWV6ZXMKY3V0X2JsdWUgPC0gcGFyICU+JSAKICBmaWx0ZXIoYmlsbGlrZW5UZWFtID09ICJCbHVlIFNvY2tzIikgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MoZXYpKSA8PSAxNUwpCgpjdXRfbWVsb24gPC0gcGFyICU+JSAKICBmaWx0ZXIoYmlsbGlrZW5UZWFtID09ICJNZWxvbmhlYWRzIikgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MoZXYpKSA8PSAxNUwpCgpjdXRfZXJpZSA8LSBwYXIgJT4lIAogIGZpbHRlcihiaWxsaWtlblRlYW0gPT0gIkVyaWUgTGFrZXJzIikgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MoZXYpKSA8PSAxNUwpCgpjdXRfcGFzdCA8LSBwYXIgJT4lIAogIGZpbHRlcihiaWxsaWtlblRlYW0gPT0gIk5hdGlvbmFsIFBhc3RpbWUiKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhldikpIDw9IDE1TCkKCmN1dF9iaWdyZWQgPC0gcGFyICU+JSAKICBmaWx0ZXIoYmlsbGlrZW5UZWFtID09ICJCaWcgUmVkIE1hY2hpbmUiKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhldikpIDw9IDE1TCkKCmN1dF9yZWJ1aWxkIDwtIHBhciAlPiUgCiAgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiUmVidWlsZGluZyBZZWFyIikgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MoZXYpKSA8PSAxNUwpCgpjdXRfZnJlZSA8LSBwYXIgJT4lIAogIGZpbHRlcihiaWxsaWtlblRlYW0gPT0gIkZyZWUgQmlyZHMiKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhldikpIDw9IDE1TCkKCmN1dF93ZXN0IDwtIHBhciAlPiUgCiAgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiV2VzdHNpZGUgTWFyYXVkZXJzIikgJT4lIAogIGZpbHRlcihyb3dfbnVtYmVyKGRlc2MoZXYpKSA8PSAxMkwpCgpjdXRfc2x1ZyA8LSBwYXIgJT4lIAogIGZpbHRlcihiaWxsaWtlblRlYW0gPT0gIkxvdWlzdmlsbGUgU2x1Z2dlcnMiKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhldikpIDw9IDExTCkKCmN1dF9ob29zIDwtIHBhciAlPiUgCiAgZmlsdGVyKGJpbGxpa2VuVGVhbSA9PSAiSG9vc2llcnMiKSAlPiUgCiAgZmlsdGVyKHJvd19udW1iZXIoZGVzYyhldikpIDw9IDEwTCkKCnByb2plY3RlZF9rZWVwZXJzIDwtIHJiaW5kKGN1dF9ibHVlLCBjdXRfbWVsb24sIGN1dF9lcmllLCBjdXRfcGFzdCwgY3V0X2JpZ3JlZCwgY3V0X3JlYnVpbGQsIGN1dF9mcmVlLCBjdXRfd2VzdCwgY3V0X3NsdWcsIGN1dF9ob29zKQoKcHJvamVjdGVkX2tlZXBlcnMgPC0gcHJvamVjdGVkX2tlZXBlcnMgJT4lIAogIHNlbGVjdChOYW1lLCBiaWxsaWtlblRlYW0pICU+JSAKICByZW5hbWUoa2VlcGluZ1RlYW0gPSBiaWxsaWtlblRlYW0pIAoKcHJvamVjdGVkX2tlZXBlcnMKCmBgYAoKYGBge3J9CnByb2plY3RlZF9kcmFmdF9lbGlnaWJsZSA8LSBwYXIgJT4lIAogIGxlZnRfam9pbihwcm9qZWN0ZWRfa2VlcGVycywgYnkgPSBqb2luX2J5KE5hbWUpKSAlPiUgCiAgZmlsdGVyKGlzLm5hKGtlZXBpbmdUZWFtKSkgJT4lIAogIHJlbG9jYXRlKGV2LCAuYWZ0ZXIgPSBwYXIpICU+JSAKICBhcnJhbmdlKGRlc2MoZXYpKSAKCnByb2plY3RlZF9kcmFmdF9lbGlnaWJsZSA8LSAKICBwcm9qZWN0ZWRfZHJhZnRfZWxpZ2libGUgJT4lIAogIG11dGF0ZShwaWNrID0gcm93X251bWJlcigpKQoKcHJvamVjdGVkX2RyYWZ0X2VsaWdpYmxlCgpgYGAKCgpgYGB7cn0KIyBSZW9yZGVyIGZvbGxvd2luZyB0aGUgdmFsdWUgb2YgYW5vdGhlciBjb2x1bW46CmdncGxvdChwcm9qZWN0ZWRfZHJhZnRfZWxpZ2libGUsIGFlcyh4ID0gcmVvcmRlcihwaWNrLCAtZXYpLCB5ID0gZXYpKSArIAogIGdlb21fcG9pbnQoKSAjKwogICNzY2FsZV94X2Rpc2NyZXRlKGJyZWFrcyA9IGxldmVscyhwaWNrKVtjKFQsIHJlcChGLCA5KSldKQogICNzY2FsZV94X2Rpc2NyZXRlKGJyZWFrcz1zZXEoMSwgMTAxLCAxMCkpICsKICAjc2NhbGVfeF9kaXNjcmV0ZSgpICsKICAjeGxpbSgxLDExMCkgIysKICAjdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCwgdmp1c3QgPSAwLjUsIGhqdXN0ID0gMSkpICMrCiAgI3NjYWxlX3hfY29udGludW91cygKICAgICNicmVha3MgPSBzZXEoMSwgMTAxLCAxMCkjLAogICAgI21pbm9yX2JyZWFrcyA9IHNlcSg4LjUsIDM1LjUsIDEpCiAgIykgCgpnZ3Bsb3QocHJvamVjdGVkX2RyYWZ0X2VsaWdpYmxlLCBhZXMoeCA9IHBpY2ssIHkgPSBldikpICsgCiAgc2NhbGVfeF9jb250aW51b3VzKGJyZWFrcz1zZXEoMSwgMTAxLCAxMCkpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDkwLCB2anVzdCA9IDAuNSwgaGp1c3QgPSAxKSkgKwogIHhsaW0oMCwxMDApICsKICBnZW9tX3Ntb290aChmb3JtdWxhID0geSB+IGxvZyh4KSkgKwogIGdlb21fcG9pbnQoKQogICAgCmBgYAoKCmBgYHtyfQoKCmBgYAoK